package main

import (
	client2 "DifProject/client"
	pkg2 "DifProject/pkg"
	"encoding/json"
	"fmt"
	"github.com/gorilla/websocket"
	"io"
	"net/http"
	"sort"
)

var UP = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
	// 允许跨域
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
}

var hub = make(map[string]map[string]*client2.Client)

//var tokens = make(map[string][]string)

//var clients client2.Clients

// 用户认证
func getAuthentication(w http.ResponseWriter, r *http.Request) {
	var client client2.Client
	var pkg pkg2.Pkg

	// 设置允许跨域的来源，*表示允许所有来源
	w.Header().Set("Access-Control-Allow-Origin", "*")
	// 设置允许的请求方法
	w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
	// 设置允许的请求头
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
	body, err := io.ReadAll(r.Body)
	if err != nil {
		//fmt.Println("read message error")
		return
	}
	err = json.Unmarshal(body, &pkg)
	if err != nil {
		//fmt.Println("用户认证请求读取失败")
		return
	}

	err = r.ParseForm()
	if err != nil {
		return
	}
	queryParams := r.URL.Query()
	var roomId string
	if len(queryParams) > 0 {
		roomId = queryParams.Get("roomId")
		client.RoomId = roomId
	}

	pkgType := pkg.Type
	client = pkg.Data
	client.Hub = hub
	switch pkgType {
	case pkg2.Authentication:
		//用户认证
		client.GetAuthentication()

		if client.RoomId == "" {
			client.IsOwner = "1"
		} else {
			client.IsOwner = "0"
		}

		if client.IsOwner == "0" && len(hub[client.RoomId]) >= 2 {
			postPkg := pkg2.PostPkg{
				Type: "joinError",
				Code: "300",
			}
			m, err := json.Marshal(postPkg)
			if err != nil {
				//fmt.Println("jsonMarshal error")
				return
			}
			w.Write(m)
			return
		}

		//返回数据
		postPkg := pkg2.PostPkg{
			Type: pkg2.Authentication,
			Code: "200",
			Data: client,
		}
		m, err := json.Marshal(postPkg)
		if err != nil {
			//fmt.Println("jsonMarshal error")
			return
		}
		w.Write(m)

	case "exitRoom":
		if pkg.Data.IsOwner == "0" {
			fmt.Println("退出成功")
			//将该用户从房间中退出

			var uid string
			for key, _ := range hub[pkg.Data.RoomId] {
				if key == pkg.Data.Uuid {
					continue
				}
				uid = key
			}

			postPkg := pkg2.PostPkg{
				Type: "otherExit",
				Code: "200",
				Data: pkg.Data,
			}
			fmt.Println("@@@", pkg.Data.RoomId)
			hub[pkg.Data.RoomId][uid].Conn.WriteJSON(postPkg)
			fmt.Println("发送成功")

			delete(hub[pkg.Data.RoomId], pkg.Data.Uuid)

		} else if pkg.Data.IsOwner == "1" {
			fmt.Println("房主退出")
			if len(hub[pkg.Data.RoomId]) == 1 {
				//退出房间
				delete(hub[pkg.Data.RoomId], pkg.Data.Uuid)

				//注销房间
				delete(hub, pkg.Data.RoomId)

			} else if len(hub[pkg.Data.RoomId]) == 2 {

				var uid string
				for key, _ := range hub[pkg.Data.RoomId] {
					if key == pkg.Data.Uuid {
						continue
					}
					uid = key
				}

				postPkg1 := pkg2.PostPkg{
					Type: "exitRoom",
					Code: "200",
					Data: pkg.Data,
				}

				hub[pkg.Data.RoomId][uid].Conn.WriteJSON(postPkg1)

				//注销房间
				delete(hub, pkg.Data.RoomId)
			}
		}
	}
}

func SocketRoom(w http.ResponseWriter, r *http.Request) {

	conn, err := UP.Upgrade(w, r, nil)

	if err != nil {
		//fmt.Println(err)
		return
	}

	for {
		//解析数据包
		var pkg pkg2.Pkg
		//读取socket请求
		err := conn.ReadJSON(&pkg)
		fmt.Println(pkg)
		if err != nil {
			return
		}
		pkgType := pkg.Type

		if pkgType == pkg2.BuildRoom || pkgType == pkg2.UpdateConn {
			pkg.Data.Hub = hub
			pkg.Data.Conn = conn
		}

		//处理请求
		switch pkgType {
		//创建、加入房间
		case pkg2.BuildRoom:
			if pkg.Data.IsOwner == "1" {
				pkg.Data.BuildRoom()

				//tokens[pkg.Data.RoomId] = append(tokens[pkg.Data.RoomId], pkg.Data.Uuid)

				postPkg := pkg2.PostPkg{
					Type: pkg2.BuildRoom,
					Code: "200",
					Data: pkg.Data,
				}

				err := pkg.Data.Conn.WriteJSON(postPkg)
				if err != nil {
					return
				}
				fmt.Println("build success")
			} else {
				pkg.Data.JoinRoom()
				var conn1 *websocket.Conn
				var conn2 *websocket.Conn
				var uid1 string

				for id := range hub[pkg.Data.RoomId] {
					if id == pkg.Data.Uuid {
						continue
					}
					uid1 = id
				}

				conn1 = hub[pkg.Data.RoomId][uid1].Conn
				conn2 = hub[pkg.Data.RoomId][pkg.Data.Uuid].Conn

				postPkg1 := pkg2.PostPkg{
					Type: "roomOwner",
					Code: "200",
					Data: *hub[pkg.Data.RoomId][uid1],
				}

				postPkg2 := pkg2.PostPkg{
					Type: "invitee",
					Code: "200",
					Data: pkg.Data,
				}
				err := conn1.WriteJSON(postPkg2)
				if err != nil {
					return
				}
				err = conn2.WriteJSON(postPkg1)
				if err != nil {
					return
				}

				fmt.Println("join success")
			}

		//开始游戏
		case pkg2.StartGame:

			var conn1 *websocket.Conn
			var conn2 *websocket.Conn

			var uid string
			for key, _ := range hub[pkg.Data.RoomId] {
				if key == pkg.Data.Uuid {
					continue
				}
				uid = key
			}
			fmt.Println("----conn1", hub[pkg.Data.RoomId][uid])
			conn1 = hub[pkg.Data.RoomId][uid].Conn
			conn2 = conn

			pkg := pkg2.StartPkg{
				Type: pkg2.StartGame,
				Code: "200",
			}

			fmt.Println("发送开始游戏1")
			conn1.WriteJSON(pkg)
			fmt.Println("发送开始游戏2")
			conn2.WriteJSON(pkg)

		//重新连接
		case pkg2.UpdateConn:
			//获取当前客户端的uid
			uid := pkg.Data.Uuid

			//更新该客户端的连接
			hub[pkg.Data.RoomId][uid].Conn = conn
			fmt.Println("更新成功")

			pkg1 := pkg2.PostPkg{
				Type: "updateConn",
				Code: "200",
				Data: *hub[pkg.Data.RoomId][uid],
			}

			var uid2 string
			for key, _ := range hub[pkg.Data.RoomId] {
				if key == pkg.Data.Uuid {
					continue
				}
				uid2 = key
			}

			pkg2 := pkg2.PostPkg{
				Type: "updateConn",
				Code: "200",
				Data: *hub[pkg.Data.RoomId][uid2],
			}
			conn.WriteJSON(pkg2)
			hub[pkg.Data.RoomId][uid2].Conn.WriteJSON(pkg1)

		//更新游戏进度
		case pkg2.GameProgress:
			//转发分数
			var uid2 string
			for key, _ := range hub[pkg.Data.RoomId] {
				if key == pkg.Data.Uuid {
					continue
				}
				uid2 = key
			}

			//更新数据
			hub[pkg.Data.RoomId][pkg.Data.Uuid].Score = pkg.Data.Score
			hub[pkg.Data.RoomId][pkg.Data.Uuid].Time = pkg.Data.Time

			//将该客户端数据转发到对方连接
			err := hub[pkg.Data.RoomId][uid2].Conn.WriteJSON(pkg)
			if err != nil {
				fmt.Println("转发失败")
				return
			}
			fmt.Println("转发成功")
		//结束游戏
		case "endGame":
			fmt.Println("游戏结束")

			var uid string
			for key, _ := range hub[pkg.Data.RoomId] {
				if key == pkg.Data.Uuid {
					continue
				}
				uid = key
			}

			hub[pkg.Data.RoomId][pkg.Data.Uuid].Score = pkg.Data.Score
			hub[pkg.Data.RoomId][pkg.Data.Uuid].Time = pkg.Data.Time

			Postpkg1 := pkg2.PostPkg{
				Type: "endGame",
				Code: "200",
				Data: *hub[pkg.Data.RoomId][pkg.Data.Uuid],
			}

			Postpkg2 := pkg2.PostPkg{
				Type: "endGame",
				Code: "200",
				Data: *hub[pkg.Data.RoomId][uid],
			}

			//给双发发送游戏结束的消息
			conn.WriteJSON(Postpkg2)

			err := hub[pkg.Data.RoomId][uid].Conn.WriteJSON(Postpkg1)
			if err != nil {
				fmt.Println(err)
				return
			}
		case "check":
			//心跳检测
			conn.WriteJSON("check")

		}
	}

}

func postList(w http.ResponseWriter, r *http.Request) {

	// 设置允许跨域的来源，*表示允许所有来源
	w.Header().Set("Access-Control-Allow-Origin", "*")
	// 设置允许的请求方法
	w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
	// 设置允许的请求头
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")

	body, err := io.ReadAll(r.Body)
	if err != nil {
		fmt.Println("read message error")
		return
	}

	var pkg pkg2.Pkg
	err = json.Unmarshal(body, &pkg)
	if err != nil {
		fmt.Println("序列化失败")
		return
	}

	fmt.Println("排行榜:")
	fmt.Println(pkg)
	pkgType := pkg.Type

	switch pkgType {
	case pkg2.List:

		clients := client2.Clients{}

		var uid string
		for key, _ := range hub[pkg.Data.RoomId] {
			if key == pkg.Data.Uuid {
				continue
			}
			uid = key
		}

		clients = append(clients, pkg.Data)
		clients = append(clients, *hub[pkg.Data.RoomId][uid])

		sort.Sort(clients)

		//返回数据
		clientListPkg := pkg2.PostListPkg{
			Type: pkg2.List,
			Code: "200",
			Data: clients,
		}
		marshal, err := json.Marshal(clientListPkg)
		if err != nil {
			return
		}
		w.Write(marshal)
	}
}

func main() {
	http.HandleFunc("/login", getAuthentication)

	http.HandleFunc("/ws", SocketRoom)

	http.HandleFunc("/list", postList)

	http.ListenAndServe(":8887", nil)
}
